<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>宏通通话</title>
</head>
<style>
  body {
    font-family: Arial, sans-serif;
    max-width: 100%;
    padding: 10px;
    box-sizing: border-box;
  }

  .modal {
    display: none;
    position: fixed;
    z-index: 1;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.4);
  }

  .modal-content {
    background-color: #fefefe;
    margin: 15% auto;
    padding: 20px;
    border: 1px solid #888;
    width: 80%;
    max-width: 500px;
    border-radius: 4px;
  }

  .close {
    color: #aaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
  }

  .close:hover {
    color: black;
  }

  .connection-info {
    margin-top: 15px;
    font-size: 14px;
  }

  .video-container {
    position: relative;
    width: 100%;
    height: 80vh;
    background: #000;
    overflow: hidden;
  }

  #remoteVideo {
    position: absolute;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  #localVideo {
    position: absolute;
    width: 120px;
    height: 160px;
    right: 20px;
    bottom: 80px;
    border-radius: 8px;
    border: 2px solid #fff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
    z-index: 10;
    object-fit: cover;
    touch-action: none;
    user-select: none;
  }

  .button-group {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    margin-bottom: 30px;
    justify-content: center;
    padding: 15px;
    background: rgba(255, 255, 255, 0.9);
    border-radius: 50px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  }

  .button-group button {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: #07C160;
    color: white;
    font-size: 14px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: none;
    cursor: pointer;
    transition: all 0.3s ease;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    position: relative;
    overflow: hidden;
  }

  .button-group button span.icon {
    font-size: 28px;
    margin-bottom: 5px;
  }

  .button-group button span.text {
    font-size: 12px;
  }

  .button-group button:hover {
    transform: translateY(-5px) scale(1.05);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
    background: #06AD56;
  }

  .button-group button:active {
    transform: translateY(2px) scale(0.98);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }

  .button-group button.toggle {
    background: #07C160;
  }

  .button-group button.toggle.off {
    background: #FA5151;
  }

  .button-group button:disabled {
    background: #e0e0e0;
    color: #9e9e9e;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
  }

  .control-panel {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    padding: 15px 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 100;
  }

  .control-panel button {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    margin: 0 12px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    font-size: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    position: relative;
    overflow: hidden;
  }

  .control-panel button:hover {
    transform: translateY(-4px) scale(1.05);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
    background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
  }

  .control-panel button:active {
    transform: translateY(1px) scale(0.98);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }

  .control-panel button.toggle {
    background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
  }

  .control-panel button.toggle.off {
    background: linear-gradient(135deg, #f56565 0%, #e53e3e 100%);
  }

  .control-panel button::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0%, transparent 70%);
    opacity: 0;
    transition: opacity 0.3s;
  }

  .control-panel button:hover::before {
    opacity: 1;
  }

  .control-panel button::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 5px;
    height: 5px;
    background: rgba(255, 255, 255, 0.5);
    opacity: 0;
    border-radius: 50%;
    transform: scale(1, 1) translate(-50%, -50%);
    transform-origin: 50% 50%;
  }

  .control-panel button:focus:not(:active)::after {
    animation: ripple 1s ease-out;
  }

  @keyframes ripple {
    0% {
      transform: scale(0, 0);
      opacity: 0.5;
    }

    20% {
      transform: scale(25, 25);
      opacity: 0.3;
    }

    100% {
      opacity: 0;
      transform: scale(40, 40);
    }
  }

  button:disabled {
    background: #cccccc;
    cursor: not-allowed;
  }

  button.toggle {
    background: #34a853;
  }

  button.toggle.off {
    background: #ea4335;
  }

  #log {
    margin-top: 20px;
    padding: 10px;
    border: 1px solid #ccc;
    max-height: 200px;
    overflow-y: auto;
    font-size: 14px;
    background: #f5f5f5;
  }

  .remote-status,
  .network-status {
    display: flex;
    gap: 15px;
    margin-bottom: 15px;
    justify-content: center;
  }

  html,
  body {
    margin: 0 !important;
    padding: 0 !important;
  }

  .status-indicator {
    padding: 8px 12px;
    border-radius: 4px;
    background: #f0f0f0;
    font-size: 14px;
  }

  .signal-icon {
    display: inline-block;
    width: 20px;
    height: 20px;
    margin-right: 5px;
    vertical-align: middle;
  }

  .signal-excellent {
    color: #34a853;
  }

  .signal-good {
    color: #fbbc05;
  }

  .signal-fair {
    color: #f29900;
  }

  .signal-poor {
    color: #ea4335;
  }

  @media (min-width: 768px) {
    .video-container {
      flex-direction: row;
      justify-content: center;
    }
  }
</style>

<body>
  <!-- 视频UI -->
  <div class="video-container" style="margin-bottom: 20px;">
    <video id="localVideo" autoplay muted playsinline webkit-playsinline></video>
    <video id="remoteVideo" autoplay playsinline webkit-playsinline></video>
  </div>
  <!-- 设备状态 -->
  <div class="remote-status">
    <div id="remoteMicStatus" class="status-indicator">对方麦克风: 未知</div>
    <div id="remoteCameraStatus" class="status-indicator">对方摄像头: 未知</div>
  </div>
  <!-- 网络状态 -->
  <div class="network-status">
    <div id="localNetworkStatus" class="status-indicator">本地网络: 等待连接...</div>
    <div id="remoteNetworkStatus" class="status-indicator">对方网络: 等待连接...</div>
  </div>
  <!-- 功能状态 -->
  <div class="button-group">
    <button id="startCall"><span class="icon">📞</span><span class="text">通话</span></button>
    <button id="endCall" disabled><span class="icon">📵</span><span class="text">挂断</span></button>
    <button id="toggleMic" class="toggle"><span class="icon">🎤</span><span class="text">麦克风</span></button>
    <button id="toggleCamera" class="toggle"><span class="icon">📷</span><span class="text">摄像头</span></button>
    <button id="switchCamera"><span class="icon">🔄</span><span class="text">切换</span></button>
    <button id="showConnectionInfo"><span class="icon">ℹ️</span><span class="text">信息</span></button>
  </div>
  <!-- 连接状态 -->
  <div id="connectionModal" class="modal">
    <div class="modal-content">
      <span class="close">&times;</span>
      <h3>连接信息</h3>
      <div class="connection-info" id="iceServerInfo"></div>
      <div class="connection-info" id="connectionStatus"></div>
      <div id="log"
        style="margin-top: 20px; padding: 10px; border: 1px solid #ccc; max-height: 200px; overflow-y: auto; font-size: 14px; background: #f5f5f5;">
      </div>
    </div>
  </div>
  <!-- 弹窗状态 -->
  <div id="callRequestModal" class="modal">
    <div class="modal-content" style="text-align: center;">
      <h2>来电请求</h2>
      <p>有人正在请求与您视频通话，请点击通话接受通话</p>
      <div style="margin-top: 20px;">
        <button id="acceptCall"
          style="background-color: #07C160; color: white; padding: 10px 20px; border: none; border-radius: 5px; margin-right: 10px; cursor: pointer;">接听</button>
        <button id="rejectCall"
          style="background-color: #FA5151; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">拒绝</button>
      </div>
    </div>
  </div>

  <script>
    const localVideo = document.getElementById("localVideo");

    // 小窗拖拽功能
    let isDragging = false;
    let offsetX, offsetY;
    // 触摸开始事件
    localVideo.addEventListener('touchstart', (e) => {
      isDragging = true;
      const touch = e.touches[0];
      const rect = localVideo.getBoundingClientRect();
      offsetX = touch.clientX - rect.left;
      offsetY = touch.clientY - rect.top;
      e.preventDefault();
    });
    // 触摸移动事件
    localVideo.addEventListener('touchmove', (e) => {
      if (!isDragging) return;
      const touch = e.touches[0];
      const videoContainer = document.querySelector('.video-container');
      const containerRect = videoContainer.getBoundingClientRect();
      const videoRect = localVideo.getBoundingClientRect();

      // 计算新位置
      let newX = touch.clientX - offsetX - containerRect.left;
      let newY = touch.clientY - offsetY - containerRect.top;

      // 边界检查
      newX = Math.max(0, Math.min(newX, containerRect.width - videoRect.width));
      newY = Math.max(0, Math.min(newY, containerRect.height - videoRect.height));

      // 应用新位置
      localVideo.style.left = newX + 'px';
      localVideo.style.top = newY + 'px';
      localVideo.style.right = 'auto';
      localVideo.style.bottom = 'auto';
      e.preventDefault();
    });
    // 触摸结束事件
    localVideo.addEventListener('touchend', () => {
      isDragging = false;
    });


    const remoteVideo = document.getElementById("remoteVideo");
    const startButton = document.getElementById("startCall");
    const endButton = document.getElementById("endCall");
    const toggleMicButton = document.getElementById("toggleMic");
    const toggleCameraButton = document.getElementById("toggleCamera");
    const switchCameraButton = document.getElementById("switchCamera");
    const logElement = document.getElementById("log");
    const remoteMicStatus = document.getElementById("remoteMicStatus");
    const remoteCameraStatus = document.getElementById("remoteCameraStatus");
    const localNetworkStatus = document.getElementById("localNetworkStatus");
    const remoteNetworkStatus = document.getElementById("remoteNetworkStatus");
    const showConnectionInfoBtn = document.getElementById("showConnectionInfo");
    const connectionModal = document.getElementById("connectionModal");
    const iceServerInfo = document.getElementById("iceServerInfo");
    const connectionStatus = document.getElementById("connectionStatus");
    const closeBtn = document.querySelector(".close");

    let localStream;
    let peerConnection;
    let audioTrack;
    let videoTrack;
    let remoteAudioTrack;
    let remoteVideoTrack;
    let isAlertShowed = false; // 新增节流控制变量
    let ws = new WebSocket(`wss://${window.location.host}`);

    const configuration = {
      iceServers: [
        {
          urls: "turn:47.98.220.209:3478", // 自己的 TURN 服务器
          username: "hj", // 用户名
          credential: "hj207131", // 密码
        }
      ],
    };

    // 日志函数，同时输出到控制台和页面
    function logMessage(message) {
      console.log(message);
      const logEntry = document.createElement('p');
      logEntry.textContent = message;
      logElement.appendChild(logEntry);
    }

    let currentFacingMode = 'user';

    async function getCameraStream(facingMode) {
      try {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');

        if (videoDevices.length < 2) {
          logMessage('未检测到多个摄像头设备');
          return null;
        }

        const stream = await navigator.mediaDevices.getUserMedia({
          video: { facingMode },
          audio: true
        });
        return stream;
      } catch (error) {
        logMessage(`获取摄像头流时出错: ${error.message}`);
        return null;
      }
    }

    navigator.mediaDevices
      .getUserMedia({ video: { facingMode: 'user' }, audio: true })
      .then((stream) => {
        localVideo.srcObject = stream;
        localStream = stream;
        audioTrack = stream.getAudioTracks()[0];
        videoTrack = stream.getVideoTracks()[0];
        startButton.disabled = false;
        toggleMicButton.disabled = false;
        toggleCameraButton.disabled = false;
        logMessage('成功获取本地媒体流');
      })
      .catch((error) => {
        logMessage(`访问媒体设备出错: ${error.message}`);
        startButton.disabled = true;
        toggleMicButton.disabled = true;
        toggleCameraButton.disabled = true;
      });

    function sendToServer(message) {
      if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify(message));
        logMessage(`已发送消息到服务器${message.type}`);
      } else {
        logMessage('WebSocket 连接未打开，无法发送消息');
      }
    }

    ws.onopen = () => {
      logMessage('WebSocket 连接已建立');
    };

    ws.onerror = (error) => {
      logMessage(`WebSocket 出错: ${error.message}`);
    };

    // 显示连接信息
    function showConnectionInfo() {
      if (peerConnection) {
        connectionStatus.innerHTML = `<strong>连接状态:</strong><br>ICE: ${peerConnection.iceConnectionState}<br>Signaling: ${peerConnection.signalingState}`;
      } else {
        connectionStatus.innerHTML = `<strong>连接状态:</strong><br>未建立连接`;
      }
      connectionModal.style.display = "block";
    }

    // 关闭弹窗
    closeBtn.onclick = function () {
      connectionModal.style.display = "none";
    }

    // 点击弹窗外部关闭
    window.onclick = function (event) {
      if (event.target == connectionModal) {
        connectionModal.style.display = "none";
      }
    }

    // 绑定连接信息按钮点击事件
    showConnectionInfoBtn.onclick = showConnectionInfo;

    let isCallEnded = false;

    async function handleOffer(offer) {
      try {
        logMessage('开始处理收到的offer');

        // 验证offer对象完整性
        if (!offer || typeof offer !== 'object') {
          throw new Error('无效的offer格式: 不是对象');
        }

        // 确保offer有type和sdp字段
        if (!offer.type || offer.type !== 'offer') {
          throw new Error('无效的offer类型');
        }

        // 验证SDP格式
        if (!offer.sdp || typeof offer.sdp !== 'string') {
          throw new Error('无效的SDP格式: 不是字符串');
        }

        // 检查SDP格式有效性
        const sdp = offer.sdp.trim();
        if (!sdp) {
          throw new Error('无效的SDP格式: 空字符串');
        }

        if (!sdp.startsWith('v=')) {
          throw new Error('无效的SDP格式: 必须以v=开头');
        }

        if (sdp.length < 10) {
          throw new Error('无效的SDP格式: 长度不足');
        }

        // 检查SDP是否包含必要字段
        if (!sdp.includes('m=')) {
          throw new Error('无效的SDP格式: 缺少媒体描述(m=)');
        }

        if (!sdp.includes('o=')) {
          throw new Error('无效的SDP格式: 缺少源描述(o=)');
        }

        // 创建新的RTCPeerConnection
        const PeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
        peerConnection = new PeerConnection(configuration);

        // 添加本地流
        if (localStream) {
          localStream.getTracks().forEach(track => {
            peerConnection.addTrack(track, localStream);
          });
        }

        // 创建RTCSessionDescription对象
        const sessionDescription = new RTCSessionDescription({
          type: 'offer',
          sdp: offer.sdp
        });

        // 设置远程描述
        await peerConnection.setRemoteDescription(sessionDescription);
        logMessage('已设置远程描述');

        // 创建answer
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        logMessage('已创建并设置本地answer');

        // 发送answer到服务器
        sendToServer({
          type: 'answer',
          sdp: answer.sdp
        });

        // 设置ICE候选收集
        peerConnection.onicecandidate = (event) => {
          if (event.candidate) {
            sendToServer({
              type: 'candidate',
              candidate: event.candidate
            });
          }
        };

        // 处理远程流
        peerConnection.ontrack = (event) => {
          remoteVideo.srcObject = event.streams[0];
          remoteAudioTrack = event.streams[0].getAudioTracks()[0];
          remoteVideoTrack = event.streams[0].getVideoTracks()[0];
          logMessage('已收到远程流');
        };

        return true;
      } catch (error) {
        logMessage(`处理offer时出错: ${error.message}`);
        if (peerConnection) {
          peerConnection.close();
          peerConnection = null;
        }
        throw error;
      }
    }

    ws.onmessage = (event) => {
      const message = JSON.parse(event.data);
      logMessage(`收到服务器消息: ${message.type}`);

      if (message.type === 'offer') {
        // 显示来电请求弹窗
        document.getElementById('callRequestModal').style.display = 'block';

        // 绑定接听按钮事件
        document.getElementById('acceptCall').onclick = () => {
          document.getElementById('callRequestModal').style.display = 'none';
          startButton.click();
        }
      } else if (message.type === 'rejectCall') {
        console.log('收到拒绝消息');
        logMessage(`对方已拒绝通话: ${message.reason || '无原因'}`);
        // 重置通话状态
        startButton.disabled = false;
        endButton.disabled = true;
        toggleMicButton.disabled = false;
        toggleCameraButton.disabled = false;

        // 清理可能的残留连接
        if (peerConnection) {
          peerConnection.close();
          peerConnection = null;
        }

        // 更新对方状态显示
        remoteMicStatus.textContent = '对方麦克风: 未知';
        remoteCameraStatus.textContent = '对方摄像头: 未知';
      }

      // 绑定拒绝按钮事件
      document.getElementById('rejectCall').onclick = () => {
        document.getElementById('callRequestModal').style.display = 'none';
        try {
          sendToServer({
            type: 'rejectCall',
            // reason: '用户手动拒绝'
          });

          // // 重置通话状态
          // startButton.disabled = false;
          // endButton.disabled = true;
          // toggleMicButton.disabled = false;
          // toggleCameraButton.disabled = false;

          // // 清理可能的残留连接
          // if (peerConnection) {
          //   peerConnection.close();
          //   peerConnection = null;
          // }

          // // 更新对方状态显示
          // remoteMicStatus.textContent = '对方麦克风: 未知';
          // remoteCameraStatus.textContent = '对方摄像头: 未知';
          // remoteCameraStatus.textContent = '对方摄像头: 未知';

          logMessage('已拒绝来电，状态已重置');
        } catch (error) {
          logMessage(`拒绝来电时出错: ${error.message}`);
        }
      };


    }


    ws.onclose = () => {
      if (isCallEnded) return;
      isCallEnded = true;

      logMessage('WebSocket 连接已关闭');

      // 清理媒体流和DOM元素
      if (localStream) {
        localStream.getTracks().forEach(track => track.stop());
        localStream = null;
      }
      if (remoteVideo.srcObject) {
        remoteVideo.srcObject.getTracks().forEach(track => track.stop());
        remoteVideo.srcObject = null;
      }
      if (peerConnection) {
        peerConnection.close();
        peerConnection = null;
      }

      // 重置按钮状态
      startButton.disabled = false;
      endButton.disabled = true;
      toggleMicButton.disabled = true;
      toggleCameraButton.disabled = true;

      // 清空日志但保留最后一条消息
      const lastMessage = logElement.lastChild?.textContent || '';
      logElement.innerHTML = '';
      if (lastMessage) {
        const logEntry = document.createElement('p');
        logEntry.textContent = lastMessage;
        logElement.appendChild(logEntry);
      }
    };

    startButton.onclick = async () => {
      try {
        // 重置通话状态
        isCallEnded = false;
        // 清理旧连接
        if (peerConnection) {
          peerConnection.close();
          peerConnection = null;
        }
        logMessage('开始建立通话...');
        const PeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
        if (!PeerConnection) {
          logMessage('当前浏览器不支持 WebRTC');
          return;
        }
        peerConnection = new PeerConnection(configuration);
        logMessage('已创建 RTCPeerConnection 实例');

        // 定时获取网络状态
        setInterval(async () => {
          if (peerConnection) {
            try {
              const stats = await peerConnection.getStats();
              let localStats = {};
              let remoteStats = {};

              stats.forEach(report => {
                if (report.type === 'inbound-rtp') {
                  remoteStats = {
                    bitrate: report.bytesReceived * 8 / 1000,
                    packetsLost: report.packetsLost,
                    jitter: report.jitter
                  };
                } else if (report.type === 'outbound-rtp') {
                  localStats = {
                    bitrate: report.bytesSent * 8 / 1000,
                    packetsLost: report.packetsLost
                  };
                }
              });

              function getNetworkQuality(stats) {
                if (!stats.bitrate) return 'poor';

                const qualityScore = stats.bitrate / 100 -
                  (stats.packetsLost || 0) * 0.5 -
                  (stats.jitter || 0) * 0.1;

                if (qualityScore > 3) return 'excellent';
                if (qualityScore > 2) return 'good';
                if (qualityScore > 1) return 'fair';
                return 'poor';
              }

              if (Object.keys(localStats).length > 0) {
                const quality = getNetworkQuality(localStats);
                localNetworkStatus.innerHTML = `
                  <span class="signal-icon signal-${quality}">📶</span>
                  <span>本地网络: ${quality === 'excellent' ? '优' :
                    quality === 'good' ? '良' :
                      quality === 'fair' ? '中' : '差'}</span>
                `;
                logMessage(`本地网络质量: ${localStats.bitrate.toFixed(2)}kbps 丢包${localStats.packetsLost || 0} 抖动${localStats.jitter?.toFixed(3) || 0}`);
              }

              if (Object.keys(remoteStats).length > 0) {
                const quality = getNetworkQuality(remoteStats);
                remoteNetworkStatus.innerHTML = `
                  <span class="signal-icon signal-${quality}">📶</span>
                  <span>对方网络: ${quality === 'excellent' ? '优' :
                    quality === 'good' ? '良' :
                      quality === 'fair' ? '中' : '差'}</span>
                `;
                logMessage(`对方网络质量: ${remoteStats.bitrate.toFixed(2)}kbps 丢包${remoteStats.packetsLost || 0} 抖动${remoteStats.jitter?.toFixed(3) || 0}`);
              }
            } catch (error) {
              logMessage(`获取网络状态出错: ${error.message}`);
            }
          }
        }, 1000);

        // 添加本地流到 PeerConnection
        if (localStream) {
          localStream.getTracks().forEach((track) => {
            peerConnection.addTrack(track, localStream);
          });
          logMessage('已将本地媒体流添加到 RTCPeerConnection');
        } else {
          logMessage('本地媒体流不可用');
          return;
        }

        // 监听 ICE 候选
        peerConnection.onicecandidate = (event) => {
          if (event.candidate) {
            sendToServer({
              type: "new-ice-candidate",
              candidate: event.candidate,
            });
            logMessage('发现新的 ICE 候选，已发送到服务器');
          }
        };

        // 监听 ICE 连接状态
        peerConnection.oniceconnectionstatechange = () => {
          logMessage(`ICE 连接状态: ${peerConnection.iceConnectionState}`);
          if (peerConnection.iceConnectionState === 'failed') {
            logMessage('ICE 连接失败，请考虑使用 TURN 服务器');
          }
        };

        // 接收远程流
        peerConnection.ontrack = (event) => {
          logMessage('收到远程媒体流');
          remoteVideo.srcObject = event.streams[0];

          // 更新远程轨道状态
          if (event.track.kind === 'audio') {
            remoteAudioTrack = event.track;
            updateRemoteStatus();
          } else if (event.track.kind === 'video') {
            remoteVideoTrack = event.track;
            updateRemoteStatus();
          }
        };

        // 更新远程设备状态显示
        function updateRemoteStatus() {
          if (remoteAudioTrack) {
            remoteMicStatus.textContent = `对方麦克风: ${remoteAudioTrack.enabled ? '开启' : '关闭'}`;
          }
          if (remoteVideoTrack) {
            remoteCameraStatus.textContent = `对方摄像头: ${remoteVideoTrack.enabled ? '开启' : '关闭'}`;
          }
        }

        // 创建 offer 并发送给对方
        const offer = await peerConnection.createOffer();
        logMessage('已创建 offer');
        await peerConnection.setLocalDescription(offer);
        logMessage('已设置本地描述 (offer)');
        sendToServer({ type: "offer", sdp: peerConnection.localDescription });

        ws.onmessage = async (message) => {
          try {
            const data = JSON.parse(message.data);
            console.log(message, 'message')
            logMessage(`收到服务器消息${data.type}`);
            if (data.type === "offer") {
              await peerConnection.setRemoteDescription(
                new RTCSessionDescription(data.sdp)
              );
              logMessage('已设置远程描述 (offer)');
              const answer = await peerConnection.createAnswer();
              logMessage('已创建 answer');
              await peerConnection.setLocalDescription(answer);
              logMessage('已设置本地描述 (answer)');
              sendToServer({
                type: "answer",
                sdp: peerConnection.localDescription,
              });
            } else if (data.type === "answer") {
              await peerConnection.setRemoteDescription(
                new RTCSessionDescription(data.sdp)
              );
              logMessage('已设置远程描述 (answer)');
            } else if (data.type === "rejectCall") {
              // 处理拒绝消息
              logMessage(`对方已拒绝通话: ${data.reason || '无原因'}`);
              // alert('对方拒绝了您的呼叫');
              return endCall(false);
              // 重置通话状态
              isCallEnded = false;
              startButton.disabled = false;
              endButton.disabled = true;
              toggleMicButton.disabled = false;
              toggleCameraButton.disabled = false;
              // 清理连接实例
              if (peerConnection) {
                peerConnection.close();
                peerConnection = null;
              }

              // 清理可能的残留连接
              if (peerConnection) {
                peerConnection.close();
                peerConnection = null;
              }
              // 更新对方状态显示
              remoteMicStatus.textContent = '对方麦克风: 未知';
              remoteCameraStatus.textContent = '对方摄像头: 未知';
              logMessage('已拒绝来电，状态已重置')



            } else if (data.type === "new-ice-candidate") {
              try {
                await peerConnection.addIceCandidate(
                  new RTCIceCandidate(data.candidate)
                );
                logMessage('已添加接收到的 ICE 候选');
              } catch (error) {
                logMessage(`添加接收到的 ICE 候选时出错: ${error.message}`);
              }
            } else if (data.type === "end-call") {
              // 收到对方挂断请求，执行挂断逻辑
              endCall();
            } else if (data.type === "device-status") {
              // 更新远程设备状态
              if (remoteAudioTrack) {
                remoteAudioTrack.enabled = data.audioEnabled;
              }
              if (remoteVideoTrack) {
                remoteVideoTrack.enabled = data.videoEnabled;
              }
              updateRemoteStatus();
            }
          } catch (error) {
            logMessage(`解析 WebSocket 消息时出错: ${error.message}`);
          }
        };

        startButton.disabled = true;
        endButton.disabled = false;
      } catch (error) {
        logMessage(`启动通话时出错: ${error.message}`);
      }
    };

    // 挂断函数
    function endCall(isend = true) {
      if (isAlertShowed) return;
      isAlertShowed = true;

      if (peerConnection) {
        peerConnection.close();
        peerConnection = null;
      }

      if (localStream) {
        localStream.getTracks().forEach(track => track.stop());
        localStream = null;
      }

      sendToServer({ type: "end-call" });

      navigator.mediaDevices.getUserMedia({ video: true, audio: true })
        .then(stream => {
          localVideo.srcObject = stream;
          localStream = stream;
          audioTrack = stream.getAudioTracks()[0];
          videoTrack = stream.getVideoTracks()[0];
          toggleMicButton.disabled = false;
          toggleCameraButton.disabled = false;
          toggleMicButton.classList.remove('off');
          toggleMicButton.textContent = '麦克风开启';
          toggleCameraButton.classList.remove('off');
          toggleCameraButton.textContent = '摄像头开启';
          logMessage('已重新获取本地媒体流');
        })
        .catch((error) => {
          logMessage(`重新获取媒体流时出错: ${error.message}`);
        })
        .finally(() => {
          // 完全重置页面状态
          // 移除原有的alert和reload
          if(isend){
            alert('通话已结束');
          }else{
            alert('对方拒绝了您的呼叫');
          }
          location.reload();
        });
    }

    // 绑定挂断按钮点击事件
    endButton.onclick = endCall;

    // 麦克风开关控制
    toggleMicButton.onclick = () => {
      if (audioTrack) {
        audioTrack.enabled = !audioTrack.enabled;
        if (audioTrack.enabled) {
          toggleMicButton.classList.remove('off');
          toggleMicButton.textContent = '麦克风开启';
          logMessage('麦克风已开启');
        } else {
          toggleMicButton.classList.add('off');
          toggleMicButton.textContent = '麦克风关闭';
          logMessage('麦克风已关闭');
        }
        // 发送设备状态更新
        sendToServer({
          type: "device-status",
          audioEnabled: audioTrack.enabled,
          videoEnabled: videoTrack ? videoTrack.enabled : false
        });
      }

    };

    // 切换摄像头
    switchCameraButton.onclick = async () => {
      try {
        currentFacingMode = currentFacingMode === 'user' ? 'environment' : 'user';
        const newStream = await getCameraStream(currentFacingMode);
        if (newStream) {
          // 获取新的视频轨道
          const newVideoTrack = newStream.getVideoTracks()[0];

          // 替换PeerConnection中的视频轨道
          if (peerConnection) {
            const senders = peerConnection.getSenders();
            const videoSender = senders.find(s => s.track && s.track.kind === 'video');
            if (videoSender) {
              await videoSender.replaceTrack(newVideoTrack);
            }
          }

          // 更新本地视频显示
          localVideo.srcObject = newStream;
          localStream = newStream;
          videoTrack = newVideoTrack;
          logMessage('摄像头已切换');
        }
      } catch (error) {
        logMessage(`切换摄像头时出错: ${error.message}`);
      }
    };

    // 摄像头开关控制
    toggleCameraButton.onclick = () => {
      if (videoTrack) {
        videoTrack.enabled = !videoTrack.enabled;
        if (videoTrack.enabled) {
          toggleCameraButton.classList.remove('off');
          toggleCameraButton.textContent = '摄像头开启';
          logMessage('摄像头已开启');
        } else {
          toggleCameraButton.classList.add('off');
          toggleCameraButton.textContent = '摄像头关闭';
          logMessage('摄像头已关闭');
        }
        // 发送设备状态更新
        sendToServer({
          type: "device-status",
          audioEnabled: audioTrack ? audioTrack.enabled : false,
          videoEnabled: videoTrack ? videoTrack.enabled : false
        });
      }
    };
  </script>
</body>

</html>
